package com.shhm.common.utils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.benmanes.caffeine.cache.Cache;
import com.shhm.common.entity.admin.SysRoleOperatePerms;
import com.shhm.common.entity.system.SysRedisCache;
import com.shhm.common.mapper.SysRoleOperatePermsMapper;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author JackZ
 * @version 1.0
 * @description: TODO
 * @date 2025/9/13 下午3:21
 */
public class SysPermsUtil {
    /**
     * 查询目标uri匹配权限对象函数
     * 优先规则匹配：精确匹配 > 前缀匹配+请求URI最长 > 前缀匹配
     * @param list 权限列表
     * @param requestUri 需要查询的uri地址
     * @return 对象
     */
    public static SysRoleOperatePerms getOperatePermsObjectByURI(
            List<SysRoleOperatePerms> list,
            String requestUri
    ){
        if (list==null||list.isEmpty()||requestUri==null) return null;
        Set<SysRoleOperatePerms> perms= new HashSet<>(list);

        SysRoleOperatePerms res=null;
        for (SysRoleOperatePerms perm : perms) {
            if (Objects.equals(perm.getMatchMethod(), "exact") && requestUri.equals(perm.getRequestUri())) {
                res = perm;
                break;
            } else if (Objects.equals(perm.getMatchMethod(), "prefix") && requestUri.startsWith(perm.getRequestUri() + "/")) {
                if (res == null || res.getRequestUri().length() < perm.getRequestUri().length()) {
                    res = perm; // 选择更具体的前缀匹配
                }
            }
        }
        return res;
    }

    /**
     * 根据角色列表获取权限最大的对象
     *
     * @param roles      用户的角色列表
     * @param localCache 本地缓存
     * @param requestUri 请求的 URI 地址
     * @return 权限最大的对象
     */
    public static SysRoleOperatePerms getOperatePermsObjectByRoles(
            List<String> roles,
            Cache<String, List<SysRoleOperatePerms>> localCache,
            RedisTemplate<String, String> redisTemplate,
            SysRoleOperatePermsMapper roleOperatePermsMapper,
            String requestUri
    ) {
        Set<SysRoleOperatePerms> permsSet = new HashSet<>();

        // 遍历角色列表，获取每个角色的权限对象
        for (String role : roles) {
            role = role.substring(5);
            // 1. 尝试从本地缓存中获取权限列表
            List<SysRoleOperatePerms> permsList = localCache.getIfPresent(LocalCacheUtil.CACHE_PERMS_KEY_PREFIX + role);
            if (permsList == null || permsList.isEmpty()) {
                // 2. 如果本地缓存未命中，尝试从 Redis 中获取
                String redisKey = RedisUtil.REDIS_OPERATE_PERMS_KEY + role;
                SysRedisCache src = new SysRedisCache();
                src.setLimit(100);
                src.setCacheKey(redisKey);
                permsList= RedisUtil.getPrefixData(redisTemplate, src, SysRoleOperatePerms.class);

                if (permsList == null || permsList.isEmpty()) {
                    // 3. 如果 Redis 也未命中，从数据库中加载权限列表
                    LambdaQueryWrapper<SysRoleOperatePerms> query = new LambdaQueryWrapper<>();
                    query.eq(SysRoleOperatePerms::getRoleKey, role);
                    permsList = roleOperatePermsMapper.selectList(query);

                    if (permsList != null && !permsList.isEmpty()) {

                        // 将权限列表写入 Redis 和本地缓存
                        RedisUtil.flushSysRoleOperatePerms(permsList, redisTemplate);
                        LocalCacheUtil.flushOpePermsLocalCache(localCache, permsList);
                    }
                } else {
                    RedisUtil.flushSysRoleOperatePerms(permsList, redisTemplate);
                }
            }

            // 获取当前角色的匹配权限对象
            SysRoleOperatePerms matchedPerm = getOperatePermsObjectByURI(permsList, requestUri);
            if (matchedPerm != null) {
                permsSet.add(matchedPerm);
            }
        }

        // 从集合中选择权限最大的对象
        SysRoleOperatePerms result = null;
        for (SysRoleOperatePerms perm : permsSet) {
            if (result == null || isHigherPriority(perm, result)) {
                result = perm; // 更新为更高优先级的对象
            }
        }

        return result;
    }

    /**
     * 判断权限对象是否具有更高的优先级
     *
     * @param perm1 当前权限对象
     * @param perm2 已选中的权限对象
     * @return true 表示 perm1 的优先级高于 perm2
     */
    private static boolean isHigherPriority(SysRoleOperatePerms perm1, SysRoleOperatePerms perm2) {
        if (perm2 == null) return true; // 如果 perm2 为空，perm1 自动优先

        // 比较权限字符串的优先级
        String operateStr1 = perm1.getOperateStr();
        String operateStr2 = perm2.getOperateStr();

        // 规则："*" 的优先级最高
        if ("*".equals(operateStr1) && !"*".equals(operateStr2)) {
            return true;
        } else if (!"*".equals(operateStr1) && "*".equals(operateStr2)) {
            return false;
        }

        // 如果权限字符串相同，则比较权限数量（以 ":" 分隔的数量）
        int count1 = operateStr1.split(":").length;
        int count2 = operateStr2.split(":").length;
        return count1 > count2;
    }


    public static void flushOperatePermsCache(
            Cache<String, List<SysRoleOperatePerms>> localCache,
            RedisTemplate<String, String> redisTemplate,
            SysRoleOperatePermsMapper roleOperatePermsMapper
    ){
        List<SysRoleOperatePerms> list = roleOperatePermsMapper.selectList(null);
        RedisUtil.flushSysRoleOperatePerms(list,redisTemplate);
        Map<String, List<SysRoleOperatePerms>> roleOpeMap = list.stream().collect(Collectors.groupingBy(SysRoleOperatePerms::getRoleKey));
        roleOpeMap.forEach((k,v)->localCache.put(LocalCacheUtil.CACHE_PERMS_KEY_PREFIX+k,v));


        SysRedisCache src = new SysRedisCache();
        src.setLimit(100);
        src.setCacheKey(RedisUtil.REDIS_OPERATE_PERMS_KEY+"*");
        System.out.println("======= update cache permission info =======\n" +
                "\nRedis -> ADMIN role operate info at:"+RedisUtil.getPrefixData(redisTemplate,src,SysRoleOperatePerms.class)+
                "\nLocalCache -> ADMIN role operate info at:"+localCache.getIfPresent(LocalCacheUtil.CACHE_PERMS_KEY_PREFIX+"ADMIN")
        );
    }

}
